package org.eclipse.emf.cdo.ui.merge.actions;

import java.util.ArrayList;
import java.util.Map;

import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.internal.ui.dialogs.BranchSelectionDialog;
import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.ui.merge.CDOChangeSetProcessor;
import org.eclipse.emf.cdo.ui.merge.CDOConflictProcessor;
import org.eclipse.emf.cdo.ui.merge.DefaultCDOUIMerger;
import org.eclipse.emf.cdo.ui.merge.MergeTreeParent;
import org.eclipse.emf.cdo.ui.merge.TreeObject;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger.Conflict;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger.ConflictException;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.IWorkbenchPage;

/**
 * Provides the action of the two interface buttons "Merge" and "Commit" when they are pressed.
 * @author Thomas Halmetschlager
 *
 */
public class MergeUIActions {
	
	/** The target branch point. */
	CDOBranchPoint targetBranchPoint;
	
	/** The result. */
	private CDOChangeSetData result;
	
	/** The conflicts. */
	private Map<CDOID, Conflict> conflicts;
	
	/** The session. */
	private CDOSession session; 
	
	/** The source branch. */
	private CDOBranch sourceBranch;
	
	/** The target branch. */
	private CDOBranch targetBranch;
	
	/** The page. */
	private IWorkbenchPage page;
	
	/** The merger. */
	private DefaultCDOUIMerger merger;
	
	/** The data ready flag. */
	private boolean dataReady;
	
	/** The transaction. */
	private  CDOTransaction transaction;
	
	/** The CDO processor. */
	private CDOChangeSetProcessor cdoproc;
	
	
	/**
	 * Instantiates a new merge ui actions.
	 *
	 * @param page the workbench page
	 */
	public MergeUIActions(IWorkbenchPage page){
		targetBranchPoint = null;
		result = null;
		conflicts = null;
		sourceBranch=null;
		targetBranch=null;
		dataReady = false;
		this.page = page;
		session = (CDOSession)IPluginContainer.INSTANCE.getElement("org.eclipse.emf.cdo.sessions", "cdo",
        "tcp://localhost:2036?repositoryName=repo1&automaticPackageRegistry=true");
		merger = null;
	}
	
	/**
	 * Gets the result.
	 *
	 * @return the result
	 */
	public CDOChangeSetData getResult() {
		return result;
	}

	/**
	 * Gets the conflicts.
	 *
	 * @return the conflicts
	 */
	public Map<CDOID, Conflict> getConflicts() {
		return conflicts;
	}

	/**
	 * Gets the session.
	 *
	 * @return the session
	 */
	public CDOSession getSession() {
		return session;
	}

	/**
	 * Gets the source branch.
	 *
	 * @return the source branch
	 */
	public CDOBranch getSourceBranch() {
		return sourceBranch;
	}

	/**
	 * Gets the target branch.
	 *
	 * @return the target branch
	 */
	public CDOBranch getTargetBranch() {
		return targetBranch;
	}

	/**
	 * Gets the page.
	 *
	 * @return the page
	 */
	public IWorkbenchPage getPage() {
		return page;
	}

	/**
	 * Gets the merger.
	 *
	 * @return the merger
	 */
	public DefaultCDOUIMerger getMerger() {
		return merger;
	}

	/**
	 * Start of the merge action.
	 * Creates a merger and displays a window to the user from where the branch point can be selected.
	 */
	public void start(){
		CDOBranch mainBranch = session.getBranchManager().getMainBranch();
		merger = new DefaultCDOUIMerger(session);
		if(transaction != null){
			if(!transaction.isClosed()){
				transaction.close();
			}
			transaction = null;
		}
	    transaction = session.openTransaction(mainBranch);
	    sourceBranch = UserSelectBranchPoint(transaction).getBranch();
	     
	    result = null;
	    targetBranch = transaction.getBranch();
	    
	    try{
	    result = transaction.merge(sourceBranch.getHead(), merger);
	    conflicts = null;
	    }
	    catch (ConflictException e) {
	    	System.out.println(e.getMessage());
	    	result = e.getMerger().getResult();
	    	
	    	conflicts = e.getMerger().getConflicts();
	    	
	    	for(CDOID conflictID :conflicts.keySet()){
	    		Conflict conflict = conflicts.get(conflictID);
	    		
	    		System.out.println(conflict.toString());
	    	}
		}
	    catch(Exception e){
	    	e.printStackTrace();
	    }
	    finally{
	    	//transaction.close();
	    	
	    }
	   
	    
	    //transaction.commit();
	    //transaction.close();
	    dataReady = true;
	}
	
	/**
	 * Generates the list of objects to display in the tree view.
	 *
	 * @return the array list of TreeObjects
	 */
	public ArrayList<TreeObject> generate(){

		cdoproc = null;
		cdoproc = new CDOChangeSetProcessor(result, merger);
		cdoproc.setSourceChanges(merger.getSource());
		cdoproc.setTargetChanges(merger.getTarget());
		cdoproc.setSession(session);
		cdoproc.setConflicts(conflicts);
		ArrayList<TreeObject> TreeResult = new ArrayList<TreeObject>();
		
		//TreeParent root = new TreeParent("Merges");
		
		
		for(TreeObject treeLeaf : cdoproc.generateTree()){
			TreeResult.add(treeLeaf);
		}
		/*for(TreeObject treeLeaf : cdoconf.generateTree(sourceBranch,targetBranch)){
			TreeResult.add(treeLeaf);
		}*/
		
		return TreeResult;
	}
	
	/**
	 * Gets the target branch point.
	 *
	 * @return the target branch point
	 */
	public CDOBranchPoint getTargetBranchPoint() {
		return targetBranchPoint;
	}


	/**
	 * Opens a dialog from which the user can select a branch point.
	 * The selected branch point is returned
	 *
	 * @param view the currently opened view.
	 * @return the choosen CDO branch point
	 */
	public CDOBranchPoint UserSelectBranchPoint(CDOView view ){
		
		BranchSelectionDialog dialog = new BranchSelectionDialog(page, view);
		
	    if (dialog.open() == Dialog.OK)
	    {
	      targetBranchPoint = dialog.getTargetBranchPoint();
	      if (targetBranchPoint == null)
	      {
	        return null;
	      }
	    }
	    else
	    {
	    	return null;
	    }
	    
	    return targetBranchPoint;
	}

	/**
	 * Checks if is data ready.
	 *
	 * @return true, if is data ready
	 */
	public boolean isDataReady() {
		
		
		return dataReady;
	}

	/**
	 * Commits the transactions for all selected operation.
	 *
	 * @param viewer the tree view with checkboxes
	 */
	public void commit(CheckboxTreeViewer viewer) {

		// TODO check if everything is resolved.
		merger.setCommit(true);
		CDOBranch mainBranch = session.getBranchManager().getMainBranch();
		
		merger.setSelectedObjects(viewer.getCheckedElements());
		/*transaction.close();
		
		transaction = session.openTransaction(mainBranch);*/
		
		transaction.rollback();
		result = transaction.merge(sourceBranch.getHead(), merger);
		
		conflicts = merger.getConflicts();
		transaction.commit();
		merger.setCommit(false);
		//merger.setResult(result);
		//merger.findConnectedElements();
		
	}
}
